package com.xli.dto.component.model;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.xli.dto.component.TreeNode;
import com.xli.dto.component.serializer.ModelSerializer;
import com.xli.dto.component.util.TreeUtil;
import com.xli.dto.component.view.View;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@JsonSerialize(using = ModelSerializer.class)
public abstract class TreeModel<T> implements View {

    private final Map<Long,TreeNode<T>> data;

    private final Map<Long, List<TreeNode<T>>> children;

    public TreeModel() {
        this.data = new HashMap<>();

        List<TreeNode<T>> tempList = this.fetch();
        this.children = tempList.stream()
                .collect(Collectors.groupingBy(treeNode -> Optional.ofNullable(treeNode.getPid()).orElse(TreeUtil.defaultPid)));

        for (TreeNode<T> treeNode : tempList) {
            this.data.put(treeNode.getId(),treeNode);
            TreeUtil.buildTree(treeNode, this::fetchChild, this.data);
        }
    }

    public abstract List<TreeNode<T>> fetch();

    public List<TreeNode<T>> fetchChild(TreeNode<T> treeNode) {
        if (this.children.containsKey(treeNode.getId())) {
            return this.children.get(treeNode.getId());
        }
        return new ArrayList<>();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        int count = 0;
        for (Map.Entry<Long, TreeNode<T>> entry : this.data.entrySet()) {
            TreeNode<T> treeNode = entry.getValue();
            sb.append(treeNode.toString());
            if (count < this.data.size() - 1) {
                sb.append(",");
            }
            count++;
        }
        sb.append("]");
        return sb.toString();
    }
}
